package de.tudarmstadt.ukp.muip.fibqdojo.io.fibq;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.google.common.base.Optional;
import com.google.common.collect.Lists;

import de.tudarmstadt.ukp.muip.fibqdojo.Distractor;
import de.tudarmstadt.ukp.muip.fibqdojo.interfaces.IFIBQ;
import de.tudarmstadt.ukp.muip.fibqdojo.interfaces.IFIBQDistractor;
import de.tudarmstadt.ukp.muip.fibqdojo.io.Reader;
import de.tudarmstadt.ukp.muip.fibqdojo.FIBQ;

/**
 * Reads stored FIBQs from a file
 * 
 * @author Tobias Horsmann
 */
public class FIBQReader extends Reader implements FIBQ_Constants {

    private String path;
    private String separator = "";

    public FIBQReader(String path) {
        this.path = path;
    }

    public String getTokenSeparator() {
        return separator;
    }

    public List<IFIBQ> read() throws ParserConfigurationException, SAXException, IOException {
        List<IFIBQ> questions = Lists.newArrayList();
        NodeList fibqsElements = getTopHierarchyData(new File(path), FIBQ);

        for (int i = 0; i < fibqsElements.getLength(); i++) {
            Node fibq = fibqsElements.item(i);
            questions.add(processQuestion(fibq));
        }

        return questions;
    }

    private IFIBQ processQuestion(Node fibqNode) {
        NodeList childNodes = fibqNode.getChildNodes();

        List<String> tokens = Lists.newArrayList();
        List<IFIBQDistractor> distractors = Lists.newArrayList();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            if (!isElementNode(item)) {
                continue;
            }
            if (isNodeNameEqualTo((Element) item, SEPARATOR)) {
                separator = ((Element) item).getFirstChild().getNodeValue();
            }
            if (isNodeNameEqualTo((Element) item, SENTENCE)) {
                tokens = processSentence(childNodes.item(i));
                continue;
            }
            if (isNodeNameEqualTo((Element) item, DISTRACTOR)) {
                IFIBQDistractor distractor = processDistractor(item);
                distractors.add(distractor);
            }

        }
        return new FIBQ(tokens, distractors);
    }

    private List<String> processSentence(Node parent) {
        NodeList childNodes = parent.getChildNodes();
        int i = 0;
        List<String> tokens = Lists.newArrayList();
        for (; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            if (!isElementNode(item)) {
                continue;
            }
            Element element = (Element) item;
            if (isNodeNameEqualTo(element, TOKEN)) {
                String nodeValue = element.getNodeValue();
                tokens.add(nodeValue);
            }
        }
        return tokens;
    }

    private IFIBQDistractor processDistractor(Node parent) {
        String distractor = "";
        boolean isSolution = false;
        NodeList childNodes = parent.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            if (!isElementNode(item)) {
                continue;
            }
            Element element = (Element) item;
            if (isNodeNameEqualTo(element, DISTRACTOR_VALUE)) {
                Optional<String> string = getStringValueOfElement(element, DISTRACTOR_VALUE);
                if (!string.isPresent()) {
                    continue;
                }
                distractor = string.get();
                continue;
            }
            if (isNodeNameEqualTo(element, ISSOLUTION)) {
                isSolution = true;
            }
        }

        return new Distractor(distractor, isSolution);
    }

}
